package com.myclass.dynamicdatasource.configuration;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Desc: 多数据源datasource配置
 *
 * @author wujw
 * @email jiwenwu@outlook.com
 * @date 2018-12-12
 */
@Configuration
public class DataSourceConfigured {

    @Bean(name="typeOneMaster")
    @Primary
    @ConfigurationProperties("spring.datasource.type-one.master")
    public DataSource typeOneMaster(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name="typeOneSlave")
    @ConfigurationProperties("spring.datasource.type-one.slave")
    public DataSource typeOneSlave(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name="typeTwoMaster")
    @ConfigurationProperties("spring.datasource.type-two.master")
    public DataSource typeTwoMaster(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name="typeTwoSlave")
    @ConfigurationProperties("spring.datasource.type-two.slave")
    public DataSource typeTwoSlave(){
        return DataSourceBuilder.create().build();
    }

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource(){
        DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
        Map<Object,Object> dataSoutceMap = new HashMap<>(4);
        dataSoutceMap.put(DataSourceKey.type_one_master.name(),typeOneMaster());
        dataSoutceMap.put(DataSourceKey.type_one_slave.name(),typeOneSlave());
        dataSoutceMap.put(DataSourceKey.type_two_master.name(),typeTwoMaster());
        dataSoutceMap.put(DataSourceKey.type_two_slave.name(),typeTwoSlave());

        dynamicRoutingDataSource.setTargetDataSources(dataSoutceMap);

        // 将数据源的key放到数据源上下文中的key集合中，用于切换数据源时判断数据源是否有效
        DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSoutceMap.keySet());

        //此处待优化

        // 目的将所有的从库数据源key放入到集合中，用于轮询（如果有多个从库的话）
        DynamicDataSourceContextHolder.typeOneslaveDataSourceKeys.addAll(dataSoutceMap.keySet());
        DynamicDataSourceContextHolder.typeOneslaveDataSourceKeys.remove(DataSourceKey.type_one_master.name());
        DynamicDataSourceContextHolder.typeOneslaveDataSourceKeys.remove(DataSourceKey.type_two_master.name());
        DynamicDataSourceContextHolder.typeOneslaveDataSourceKeys.remove(DataSourceKey.type_two_slave.name());

        DynamicDataSourceContextHolder.typeTwoslaveDataSourceKeys.addAll(dataSoutceMap.keySet());
        DynamicDataSourceContextHolder.typeTwoslaveDataSourceKeys.remove(DataSourceKey.type_two_master.name());
        DynamicDataSourceContextHolder.typeTwoslaveDataSourceKeys.remove(DataSourceKey.type_one_master.name());
        DynamicDataSourceContextHolder.typeTwoslaveDataSourceKeys.remove(DataSourceKey.type_one_slave.name());

        return dynamicRoutingDataSource;
    }

    /**
     * 配置 SqlSessionFactoryBean
     * 在这里是为了将 MyBatis 的 mapper 位置设置到
     * Bean 的属性中，如果没有使用 *.xml 则可以不用该配置，否则将会产生 invalid bond statement 异常
     *
     * @return the sql session factory bean
     */
    @Bean
    @ConfigurationProperties(prefix = "mybatis")
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 配置数据源，此处配置为关键配置，如果没有将 dynamicDataSource 作为数据源则不能实现切换
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapping/*.xml"));
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        return sqlSessionFactoryBean;
    }

    /**
     * 注入 DataSourceTransactionManager 用于事务管理（该工程的多数据源下，推荐将事务注解配置到方法上，否则可能不生效）
     */
    @Bean(name = "typeOneTx")
    public PlatformTransactionManager transactionManagerTypeOne() {
        return new DynamicDataSourceTransactionManager(typeOneMaster());
    }
    @Bean(name = "typeTwoTx")
    public PlatformTransactionManager transactionManagerTypeTwo() {
        return new DynamicDataSourceTransactionManager(typeTwoMaster());
    }

}
